S4 Class

Course- R Programming >

In the previous section we saw that S3 classes and objects lacked formal definition. In this section we look at S4 class which is stricter in the sense that it has a formal definition and a uniform way to create objects. This adds safety to our code and prevents us from accidentally making naive mistakes.

Defining S4 Class

S4 class is defined using the setClass() function. In R terminology, member variables are called slots. While defining a class, we need to set the name and the slots (along with class of the slot) it is going to have. Here is a simple example.

setClass("student", slots=list(name="character", age="numeric", GPA="numeric"))

In the above example, we defined a new class called student along with three slots it's going to have name, age and GPA.There are other optional arguments of setClass() which you can explore in the help section with ?setClass.

Creating S4 Objects

S4 objects are created using the new() function. Following is an example to create an object of class student defined above.

> # create an object using new()
> # provide the class name and value for slots
> s <- new("student",name="John", age=21, GPA=3.5)

> s
An object of class "student"
Slot "name":
[1] "John"

Slot "age":
[1] 21

Slot "GPA":
[1] 3.5

We can check if an object is an S4 object through the function isS4().

> isS4(s)
[1] TRUE

The function setClass() returns a generator function. This generator function (usually having same name as the class) can be used to create new objects. This function acts as a constructor.


> student <- setClass("student", slots=list(name="character", age="numeric", GPA="numeric"))

> student
class generator function for class student from package ‘.GlobalEnv
function (...) 
new("student", ...)

Now we can use this constructor function to create new objects. Note above that our constructor in turn uses the new() function to create objects. It is just a wrap around.


> student(name="John", age=21, GPA=3.5)
An object of class "student"
Slot "name":
[1] "John"

Slot "age":
[1] 21

Slot "GPA":
[1] 3.5

Accessing and Modifying Slot

Just as components of a list are accessed using $, slot of an object are accessed using @.

> s@name
[1] "John"

> s@GPA
[1] 3.5

> s@age
[1] 21

 

 
 

A slot can be modified through reassignment.

> # modify GPA
> s@GPA <- 3.7

> s
An object of class "student"
Slot "name":
[1] "John"

Slot "age":
[1] 21

Slot "GPA":
[1] 3.7

Similarly, slots can be access or modified using the slot() function.

> slot(s,"name")
[1] "John"

> slot(s,"name") <- "Paul"

> s
An object of class "student"
Slot "name":
[1] "Paul"

Slot "age":
[1] 21

Slot "GPA":
[1] 3.7

Methods and Generic Functions

As in the case of S3 class, methods for S4 class also belong to generic functions rather than the class itself. Working with S4 generics is pretty much similar to S3 generics. You can list all the S4 generic functions and methods available, using the function showMethods().

> showMethods()
Function: - (package base)

Function: != (package base)
...
Function: trigamma (package base)

Function: trunc (package base)

Writing the name of the object in interactive mode prints it. This is done using the S4 generic function show(). You can see this function in the above list. This function is the S4 analogy of the S3 print() function.

> isS4(print)
[1] FALSE

> isS4(show)
[1] TRUE

We can list all the methods of show generic function using showMethods(show).

> showMethods(show)
Function: show (package methods)
object="ANY"
object="classGeneratorFunction"
...
object="standardGeneric"
(inherited from: object="genericFunction")
object="traceable"

Writing Your Own Method

We can write our own method using setMethod() helper function. For example, we can implement our class method for the show() generic as follows.


setMethod("show",
         "student",
         function(object) {
           cat(object@name, "\n")
           cat(object@age, "years old\n")
           cat("GPA:", object@GPA, "\n")
         }
)

Now, if we write out the name of the object in interactive mode as before, the above code is executed.


> s <- new("student",name="John", age=21, GPA=3.5)

> s    # this is same as show(s)
John 
21 years old
GPA: 3.5

In this way we can write our own S4 class methods for generic functions.